package com.tyros.resource.tool;

import com.tyros.common.utils.StringUtils;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Http Range Header Parser
 *
 * @author zhangshuaiyin
 * @date 2022/2/27 21:18
 */
public class RangeParser {

    /**
     * 解析 HTTP range 请求头参数
     * <p>
     * Range 请求头范围：0 ~ size-1
     * 1. Range: bytes=start-end 请求start到end字节之间的数据
     * 2. Range: bytes=start- 请求start个字节之后的数据
     * 3. Range: bytes=-end 请求最后end个字节的数据
     * <p>
     * Range 请求响应：
     * 1. 响应头要设置 Content-Range: bytes start-end/size，并设置响应状态码为 206 Partial Content，
     * 2. 如果 Range 无效则返回 416 Request Range Not Satisfiable
     *
     * @param rangeHeader range请求头参数
     * @return Range 对象
     */
    public static Range parse(String rangeHeader, long fileSize) {
        // 0-99
        // 0-
        // -99
        String bytes = getBytes(rangeHeader);
        if (StringUtils.isBlank(bytes)) {
            return null;
        }

        Range range = new Range();
        range.setStart(0).setEnd(fileSize - 1);

        String[] rangeArray = StringUtils.split(bytes, "-");

        // -99
        if (bytes.startsWith("-")) {
            long end = Math.min(Long.parseLong(rangeArray[0]), fileSize - 1);
            range.setEnd(end);
        }
        // 0-
        if (bytes.endsWith("-")) {
            long start = Math.max(Long.parseLong(rangeArray[0]), 0);
            range.setStart(start);
        }
        // 0-99
        if (rangeArray.length == 2) {
            long start = Math.max(Long.parseLong(rangeArray[0]), 0);
            long end = Math.min(Long.parseLong(rangeArray[1]), fileSize - 1);
            range.setStart(start).setEnd(end);
        }

        return range;
    }

    /**
     * 获取 Range 请求头的bytes部分
     *
     * @param rangeHeader Range: bytes=start-end
     * @return start-end
     */
    private static String getBytes(String rangeHeader) {
        if (StringUtils.isBlank(rangeHeader)) {
            return null;
        }
        String regex = "bytes=(\\d*-\\d*)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(rangeHeader.trim());

        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }

    @Data
    @Accessors(chain = true)
    public static class Range {
        private long start;
        private long end;
    }
}
